package com.lcykcl.ttgen;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

public class Node implements Comparator<Node> {

	// instance variables
	private ArrayList<Node> edges;
	private int cost;
	private ArrayList<String> info;
	private String[] timeList;
	private String code;
	
	// Time List

	public Node(ArrayList<String> info) {
		// An example of info: {code, session, sec_type, sec_num, time, loc, inst}


		// set instance variable
		this.edges = new ArrayList<Node>();
		this.cost = 0;
		//instance variables from info 
		this.info = info;
		this.code = info.get(0);
		
		// I don't know where the time will be located ,so for now I set it as 2.
		this.setTimeList(info.get(4));
		// initiate timeList by using setTimeList that is pretty same with the
		// getTimeList
		// from TimeTable Layout
	}
	
	
	public String getCode(){
		return this.code;
	}

	public int getCost() {
		return this.cost;
	}

	// Expected format of the input: M1,T2
	public void setTimeList(String time) {
		String[] timeList = time.split(",");
		// M1,T2 => {"M1", "T2"} => 3
		this.timeList = timeList;
	}

	// methods
	public void addEdge(Node nd) {
		this.edges.add(nd);
	}

        /**
         * gets the edges of this Node, get their start time (e.g. M10's start time is 10), and
         * add them together, then set it as the cost of that edge.
         */
	public void setCostForMorning() {
		int totalStartTime = 0;
		int lengthOfedges = this.edges.size();
		Node edge = null;
		String timeString = "";

		for (int i = 0; i < lengthOfedges; i++) {
			edge = this.edges.get(i);
			String[] timeStrings = edge.getTimeList();

			for (int j = 0; j < timeStrings.length; j++) {
				timeString = timeStrings[j];
				int time = getStartTime(timeString);
                                //{"M1", "T2"} => 13 + 14 = 27
				totalStartTime = time + totalStartTime;
			}
			edge.setCost(totalStartTime);
			totalStartTime = 0;
		}
	}

	public void setCost(int cost) {
		this.cost = cost;

	}

	public String[] getTimeList() {
		return this.timeList;
	}
	
        /**
         * reverse the cost by putting a negative sign "-" in front of the cost.
         */
	private void reverseCost() {
		int lengthOfedges = this.edges.size(); 
		for (int i = 0; i < lengthOfedges; i++) {
			Node edge = this.edges.get(i);
			edge.setCost(0-edge.getCost());
		};
	}
	
        /**
         * returns an integer parsed from the String time.
         * e.g. String time is M10, returns 10. String time is M1, returns 13.
         * @param timeString
         * @return 
         */
	private int getStartTime(String timeString) {
		int endOfStartTime = timeString.indexOf("-");
		if (endOfStartTime == -1) {
			endOfStartTime = timeString.length();
		}
		int time = Integer.valueOf(timeString.substring(0,
				endOfStartTime));
		if (time <= 9 && time >= 1) {
			time = time + 12;
		}
		return time;
	}
	
        /**
         * returns true if this Node's time conflicts with the Node being compared.
         * @param nd
         * @return 
         */
	public boolean isConflict(Node nd) {
		String[] timeToCompare = nd.getTimeList();
		for (int i = 0; i < timeToCompare.length; i++) {
			String timeToCompare1 = timeToCompare[i];
			for (int j = 0; j < this.timeList.length; j++) {
				String timeToCompare2 = this.timeList[j];
				//if the day is same
				if (timeToCompare2.charAt(0) == timeToCompare1.charAt(0)) {
					//if itoverlapping case
					if (!( (getStartTime(timeToCompare1) <= getEndTime(timeToCompare2)) || (getStartTime(timeToCompare2) <= getEndTime(timeToCompare1)))){
						return true;
					}
				}
			}
		}
		return false;
	}
	//examples of timeToCompare: M1 returns 13 ; M1-3 returns 15
	private int getEndTime(String timeToCompare) {
		// TODO Auto-generated method stub
		int length = timeToCompare.length();
		int EndTime = Integer.valueOf(timeToCompare.substring(length -1, length));
		if (timeToCompare.indexOf("-") == -1) {
			return EndTime + 1;
		}
		return EndTime;
	}

        /**
         * gets the edges of this Node, get their start time (e.g. M10's start time is 10), 
         * and for each Node, add up the gap between this Node and all the other Nodes in edges,
         * compare the total costs, then set it as the cost of that edge.
         */
	private void setCostForPacked() {
		int lengthOfEdges = this.edges.size();
		Node edge = null;
		int totalCost = 0;
		int time = 0;
		int edgeTime = 0;
		//this => {a,b,c} the other =>{d,e} time1 = a
		for (int i = 0; i < lengthOfEdges; i++) {
			edge = this.edges.get(i);
			String [] edgeTimeList = edge.getTimeList();
			totalCost = 0;
			for (int j = 0; j < edgeTimeList.length; j++) {
				String edgeTimeString = edgeTimeList[j];
				for (int k = 0; k < this.timeList.length; k++) {
					String timeString = this.timeList[k];
					if (timeString.substring(0, 1).equals(edgeTimeString.substring(0, 1))) {
							time = getStartTime(timeString);
							edgeTime = getStartTime(edgeTimeString);
						totalCost = totalCost + Math.abs(time - edgeTime);
					}
					else{
						totalCost = totalCost + 24;
					}
				}
			}
			edge.setCost(totalCost);
		}

	}

	private void setCostForEven() {
		this.setCostForPacked();
		reverseCost();
	}

	private void setCostForNight() {
		this.setCostForMorning();
		reverseCost();

	}

	public ArrayList<Node> sortEdgesByPersona(Persona p) {

		switch (p) {
		case MORNING:
			this.setCostForMorning();
			Collections.sort(edges, this);
			return this.edges;
		case NIGHT:
			this.setCostForNight();
			Collections.sort(edges, this);
			return this.edges;
		case EVEN:
			this.setCostForEven();
			Collections.sort(edges, this);
			return this.edges;
		case PACKED:
			this.setCostForPacked();
			Collections.sort(edges, this);
			return this.edges;

		default:
			return null;
		}
	}

	@Override
	public int compare(Node nd1, Node nd2) {
		// TODO Auto-generated method stub
		return nd1.getCost() - nd1.getCost();
	}
	
	public ArrayList<String> getInfo() {
		return this.info;
	}

}
